/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.datatheorem.ohos.trustkit.reporting;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.datatheorem.ohos.trustkit.config.PublicKeyPin;
import com.datatheorem.ohos.trustkit.pinning.PinningValidationResult;

import ohos.global.icu.text.DateFormat;
import ohos.system.version.SystemVersion;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * A pinning validation failure report.
 */
public class PinningFailureReport implements Serializable {
    // Fields specific to TrustKit reports
    private static final String APP_PLATFORM = "OHOS";
    //BuildConfig.VERSION_NAME
    private static final String trustKitVersion = SystemVersion.getVersion();
    private final String appBundleId;
    private final String appVersion;
    private final String appVendorId;
    private final PinningValidationResult validationResult;

    // Fields from the HPKP spec
    private final String serverHostname;
    private final int serverPort; // Not properly returned right now and will always be 0
    private final String notedHostname;
    private final boolean includeSubdomains;
    private final boolean enforcePinning;
    private final List<String> servedCertificateChainAsPem;
    private final List<String> validatedCertificateChainAsPem;
    private final Date dateTime;
    private final Set<PublicKeyPin> knownPins;


    PinningFailureReport(String appBundleId, String appVersion,
                         String appVendorId, String hostname, int port,
                         String notedHostname, boolean includeSubdomains,
                         boolean enforcePinning, List<String> servedCertificateChain,
                         List<String> validatedCertificateChain, Date dateTime,
                         Set<PublicKeyPin> knownPins,
                         PinningValidationResult validationResult) {
        this.appBundleId = appBundleId;
        this.appVersion = appVersion;
        this.appVendorId = appVendorId;
        this.serverHostname = hostname;
        this.serverPort = port;
        this.notedHostname = notedHostname;
        this.includeSubdomains = includeSubdomains;
        this.enforcePinning = enforcePinning;
        this.servedCertificateChainAsPem = servedCertificateChain;
        this.validatedCertificateChainAsPem = validatedCertificateChain;
        this.dateTime = dateTime;
        this.knownPins = knownPins;
        this.validationResult = validationResult;
    }


    JSONObject toJson() {
        JSONObject jsonReport = new JSONObject();
        try {
            jsonReport.put("app-bundle-id", appBundleId);
            jsonReport.put("app-version", String.valueOf(appVersion));
            jsonReport.put("app-vendor-id", appVendorId);
            jsonReport.put("app-platform", APP_PLATFORM);
            jsonReport.put("trustkit-version", trustKitVersion);
            jsonReport.put("hostname", serverHostname);
            jsonReport.put("port", serverPort);
            jsonReport.put("noted-hostname", notedHostname);
            jsonReport.put("include-subdomains", includeSubdomains);
            jsonReport.put("enforce-pinning", enforcePinning);
            jsonReport.put("validation-result", validationResult.ordinal());
            jsonReport.put("date-time", DateFormat.getDateInstance(DateFormat.LONG).format(dateTime));

            JSONArray ValidatedCertificateChainAsJson = new JSONArray();
            for (String validatedCertificate : validatedCertificateChainAsPem) {
                ValidatedCertificateChainAsJson.add(validatedCertificate);
            }
            jsonReport.put("validated-certificate-chain", ValidatedCertificateChainAsJson);

            JSONArray ServedCertificateChainAsJson = new JSONArray();
            for (String validatedCertificate : servedCertificateChainAsPem) {
                ServedCertificateChainAsJson.add(validatedCertificate);
            }
            jsonReport.put("served-certificate-chain", ServedCertificateChainAsJson);

            JSONArray jsonArrayKnownPins = new JSONArray();
            for (PublicKeyPin knownPin : knownPins) {
                jsonArrayKnownPins.add("pin-sha256=\"" + knownPin.toString() + "\"");
            }
            jsonReport.put("known-pins", jsonArrayKnownPins);

        } catch (JSONException ex) {
            // Should never happen
            throw new IllegalStateException("JSON error for report: " + this.toString());
        }
        return jsonReport;
    }

    @Override
    public String toString() {
        try {
            return toJson().toString();
        } catch (JSONException e) {
            return toJson().toString();
        }
    }

    public String getNotedHostname() {
        return notedHostname;
    }

    public String getServerHostname() {
        return serverHostname;
    }

    List<String> getValidatedCertificateChainAsPem() {
        return validatedCertificateChainAsPem;
    }

    public PinningValidationResult getValidationResult() {
        return validationResult;
    }

    int getServerPort() {
        return serverPort;
    }
}

